#include "param.h"
#include "drv_misc.h"
#include "elog.h"
#include "os_sys.h"
#include "vz_log.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

ParamAdvInfo_t g_stParamAdvInfo = {0};
ParamInfo_t g_stParamInfo = {0};
bool g_bParamInit = false;
rq_lock g_lockParam;
static char s_chFileName[64] = {0};

int Param_SetAsDefault() {
  ParamInfo_t *info = &g_stParamInfo;
  ParamAdvInfo_t *info_adv = &g_stParamAdvInfo;
  info->version = PARAM_VALUE_VER;
  info->info.batt_door_alarm_en = 1;
  info->info.heart_interval = 12 * 3600;
  info->info.pro_type = PRODUCT_TYPE_HIGH;
  info->info.radar_fault_thresh = 50;
  info->info.radar_sensitivity = 50;
  info->info.radar_trig_interval = 1;
  info->info.solar_batt_valid = 1;
  info->info.timing_pic_interval = 30 * 60;
  info->info.batt_door_alarm_interval = 60 * 60;
  info->info.batt_low_thresh = 5;
  info->info.batt_low_alarm_interval = 2 * 60 * 60;
  info->info.parking_stable_interval = 60;
  info->info.power_soc_disable = 0;
  info->info.watchdog_enable = 1;
  info->info.watchdog_timeout = 300;
  info->info.radar_cover_dist = RADAR_DIST_COVER;
  info->info.radar_enter_dist = RADAR_EMPTY_ENTER_THRESHOLD;
  info->info.radar_exit_dist = RADAR_EMPTY_EXIT_THRESHOLD;
  info->info.radar_change_dist = RADAR_DIST_THRESHOLD;
  info->info.radar_stable_dist_thresh = RADAR_STABLE_THRESHOLD;
  info->info.wakeup_interval = 1;
  info->info.factory_mode = 0;
  info->info.batt_protect_thresh = 2;
  info->info.batt_low_alarm_en = true;
  info->info.radar_fault_alarm_en = true;
  info->info.radar_fault_alarm_interval = 2 * 60 * 60;
  memset(info->info.resevered, 0, sizeof(info->info.resevered));
  info_adv->version = PARAM_ADV_VALUE_VER;
  memset(info_adv->info.ntp_server, 0, 64);
  snprintf(info_adv->info.ntp_server, 64, "%s", DEFAULT_NTP_SERVER);
  info_adv->info.first_snapshot_interval = 15 * 60;
  info_adv->info.snapshot_param[0].time_begin[2] = 0;
  info_adv->info.snapshot_param[0].time_begin[1] = 0;
  info_adv->info.snapshot_param[0].time_begin[0] = 0;
  info_adv->info.snapshot_param[0].time_end[2] = 7;
  info_adv->info.snapshot_param[0].time_end[1] = 0;
  info_adv->info.snapshot_param[0].time_end[0] = 0;
  info_adv->info.snapshot_param[0].interval = 60 * 60;
  info_adv->info.snapshot_param[0].empty_snapshot_en = 0;
  info_adv->info.snapshot_param[1].time_begin[2] = 7;
  info_adv->info.snapshot_param[1].time_begin[1] = 0;
  info_adv->info.snapshot_param[1].time_begin[0] = 0;
  info_adv->info.snapshot_param[1].time_end[2] = 18;
  info_adv->info.snapshot_param[1].time_end[1] = 0;
  info_adv->info.snapshot_param[1].time_end[0] = 0;
  info_adv->info.snapshot_param[1].interval = 30 * 60;
  info_adv->info.snapshot_param[1].empty_snapshot_en = 0;
  info_adv->info.snapshot_param[2].time_begin[2] = 18;
  info_adv->info.snapshot_param[2].time_begin[1] = 0;
  info_adv->info.snapshot_param[2].time_begin[0] = 0;
  info_adv->info.snapshot_param[2].time_end[2] = 24;
  info_adv->info.snapshot_param[2].time_end[1] = 0;
  info_adv->info.snapshot_param[2].time_end[0] = 0;
  info_adv->info.snapshot_param[2].interval = 60 * 60;
  info_adv->info.snapshot_param[2].empty_snapshot_en = 0;
  info_adv->info.detect_param[0].time_begin[2] = 0;
  info_adv->info.detect_param[0].time_begin[1] = 0;
  info_adv->info.detect_param[0].time_begin[0] = 0;
  info_adv->info.detect_param[0].time_end[2] = 7;
  info_adv->info.detect_param[0].time_end[1] = 0;
  info_adv->info.detect_param[0].time_end[0] = 0;
  info_adv->info.detect_param[0].interval = 2000;
  info_adv->info.detect_param[1].time_begin[2] = 7;
  info_adv->info.detect_param[1].time_begin[1] = 0;
  info_adv->info.detect_param[1].time_begin[0] = 0;
  info_adv->info.detect_param[1].time_end[2] = 18;
  info_adv->info.detect_param[1].time_end[1] = 0;
  info_adv->info.detect_param[1].time_end[0] = 0;
  info_adv->info.detect_param[1].interval = 1000;
  info_adv->info.detect_param[2].time_begin[2] = 18;
  info_adv->info.detect_param[2].time_begin[1] = 0;
  info_adv->info.detect_param[2].time_begin[0] = 0;
  info_adv->info.detect_param[2].time_end[2] = 24;
  info_adv->info.detect_param[2].time_end[1] = 0;
  info_adv->info.detect_param[2].time_end[0] = 0;
  info_adv->info.detect_param[2].interval = 2000;
  info_adv->info.plate_event_interval = 120;
  info_adv->info.parking_out_interval = 120;
  memset(info_adv->info.resevered, 0, sizeof(info_adv->info.resevered));
  return 0;
}

static int Param_Verify(ParamInfo_t *info, ParamAdvInfo_t *adv_info) {
  if (!info) {
    return -1;
  }
  if (info->info.watchdog_timeout == 0) {
    return -1;
  }
  if (info->info.radar_cover_dist == 0) {
    return -1;
  }
  if (info->info.radar_enter_dist == 0) {
    return -1;
  }
  if (info->info.radar_exit_dist == 0) {
    return -1;
  }
  if (info->info.radar_change_dist == 0) {
    return -1;
  }
  if (info->info.radar_stable_dist_thresh == 0) {
    return -1;
  }
  if (info->info.radar_stable_dist_thresh == 0) {
    return -1;
  }
  if (info->info.wakeup_interval == 0) {
    return -1;
  }
  if ((info->info.batt_protect_thresh == 0) ||
      (info->info.batt_protect_thresh > 10)) {
    info->info.batt_protect_thresh = 2;
  }

  if (strlen(adv_info->info.ntp_server) == 0) {
    memset(adv_info->info.ntp_server, 0, 64);
    strcpy(adv_info->info.ntp_server, DEFAULT_NTP_SERVER);
  }

  if (adv_info->info.first_snapshot_interval == 0) {
    adv_info->info.first_snapshot_interval = 15 * 60;
  }

  for (int i = 0; i < 3; i++) {
    if (adv_info->info.snapshot_param[i].interval < 60) {
      adv_info->info.snapshot_param[i].interval = 30 * 60;
    }
    if ((adv_info->info.detect_param[i].interval < 300) &&
        (adv_info->info.detect_param[i].interval > 0)) {
      adv_info->info.detect_param[i].interval = 1000;
    }
  }
  if (adv_info->info.plate_event_interval == 0) {
    adv_info->info.plate_event_interval = 120;
  }
  if (adv_info->info.parking_out_interval == 0) {
    adv_info->info.parking_out_interval = 120;
  }
  return 0;
}

static void DumpParamInfo(ParamAdvInfo_t *p_adv) {
  log_v("ntp_server: %s", p_adv->info.ntp_server);
  log_v("first_snapshot_interval: %d", p_adv->info.first_snapshot_interval);
  for (int i = 0; i < 3; i++) {
    log_v("snapshot_param[%d]: %d-%d-%d to %d-%d-%d, interval:%d, empty: %d", i,
          p_adv->info.snapshot_param[i].time_begin[2],
          p_adv->info.snapshot_param[i].time_begin[1],
          p_adv->info.snapshot_param[i].time_begin[0],
          p_adv->info.snapshot_param[i].time_end[2],
          p_adv->info.snapshot_param[i].time_end[1],
          p_adv->info.snapshot_param[i].time_end[0],
          p_adv->info.snapshot_param[i].interval,
          p_adv->info.snapshot_param[i].empty_snapshot_en);
  }
  for (int i = 0; i < 3; i++) {
    log_v("detect_param[%d]: %d-%d-%d to %d-%d-%d, interval:%d", i,
          p_adv->info.snapshot_param[i].time_begin[2],
          p_adv->info.detect_param[i].time_begin[1],
          p_adv->info.detect_param[i].time_begin[0],
          p_adv->info.detect_param[i].time_end[2],
          p_adv->info.detect_param[i].time_end[1],
          p_adv->info.detect_param[i].time_end[0],
          p_adv->info.detect_param[i].interval);
  }
  log_v("plate_event_interval: %d", p_adv->info.plate_event_interval);
  log_v("parking_out_interval: %d", p_adv->info.parking_out_interval);
}

int Param_Init() {
  OS_FILE fp = NULL;
  int ret = 0;
  int file_size = 0;
  bool set_default = false;

  if (!g_bParamInit) {
    MUTEX_CREATE(g_lockParam);
    g_bParamInit = true;
  }

  sprintf(s_chFileName, "%s", PARAM_FILE_NAME);
  fp = OS_FOPEN(s_chFileName, "rb");
  if (fp) {
    file_size = OS_FSIZE(fp);
    if (file_size < sizeof(ParamInfo_t)) {
      log_w("parameter file is not valid");
      set_default = true;
      OS_FCLOSE(fp);
    } else {
      OS_FREAD(&g_stParamInfo, sizeof(ParamInfo_t), 1, fp);
      log_d("parameter file exists, read parameters");
      OS_FCLOSE(fp);
    }
  } else {
    set_default = true;
    log_w("parameter file is not valid");
  }

  if (g_stParamInfo.version != PARAM_VALUE_VER) {
    set_default = true;
    log_w("parameter file version is not matched, reset to default");
  }

  sprintf(s_chFileName, "%s", PARAM_ADV_FILE_NAME);
  fp = OS_FOPEN(s_chFileName, "rb");
  if (fp) {
    file_size = OS_FSIZE(fp);
    if (file_size < sizeof(ParamAdvInfo_t)) {
      log_w("parameter advanced file is not valid");
      set_default = true;
      OS_FCLOSE(fp);
    } else {
      OS_FREAD(&g_stParamAdvInfo, sizeof(ParamAdvInfo_t), 1, fp);
      log_w("parameter advanced file exists, read parameters");
      OS_FCLOSE(fp);
    }
  } else {
    set_default = true;
    log_w("parameter advanced file is not valid");
  }

  if (g_stParamAdvInfo.version != PARAM_ADV_VALUE_VER) {
    set_default = true;
    log_w("parameter advanced file version is not matched, reset to default");
  }

  if (Param_Verify(&g_stParamInfo, &g_stParamAdvInfo) != 0) {
    set_default = true;
    log_w("some of advanced parameters are invalid, reset to default");
  }

  if (set_default) {
    log_w("reset to default parameters");
    Param_SetAsDefault();
    ret = Param_Save();
    if (ret != 0) {
      log_e("save parameters failed");
    }
  }
  DumpParamInfo(&g_stParamAdvInfo);
  return 0;
}

int Param_AdvRead(ParamAdvInfo_t *param) {
  if (!g_bParamInit) {
    return -1;
  }
  MUTEX_LOCK(g_lockParam);
  memcpy(param, &g_stParamAdvInfo, sizeof(ParamAdvInfo_t));
  MUTEX_UNLOCK(g_lockParam);
  return 0;
}

int Param_AdvWrite(ParamAdvInfo_t *param) {
  if (!g_bParamInit) {
    return -1;
  }
  MUTEX_LOCK(g_lockParam);
  memcpy(&g_stParamAdvInfo, param, sizeof(ParamAdvInfo_t));
  MUTEX_UNLOCK(g_lockParam);
  return 0;
}

int Param_Read(ParamInfo_t *param) {
  if (!g_bParamInit) {
    return -1;
  }

  MUTEX_LOCK(g_lockParam);
  memcpy(param, &g_stParamInfo, sizeof(ParamInfo_t));
  MUTEX_UNLOCK(g_lockParam);
  return 0;
}

int Param_Write(ParamInfo_t *param) {
  if (!g_bParamInit) {
    return -1;
  }
  MUTEX_LOCK(g_lockParam);
  memcpy(&g_stParamInfo, param, sizeof(ParamInfo_t));
  MUTEX_UNLOCK(g_lockParam);
  return 0;
}

int Param_Save() {
  OS_FILE fp = NULL;
  if (!g_bParamInit) {
    return -1;
  }

  LOG_TRACE_UI(LL_INFO, LOG_ID_WR_PARAMETERS, "save new parameters");
  MUTEX_LOCK(g_lockParam);
  sprintf(s_chFileName, "%s", PARAM_FILE_NAME);
  fp = OS_FOPEN(s_chFileName, "wb+");
  if (fp) {
    OS_FWRITE(&g_stParamInfo, sizeof(ParamInfo_t), 1, fp);
    OS_FCLOSE(fp);
  }
  sprintf(s_chFileName, "%s", PARAM_ADV_FILE_NAME);
  fp = OS_FOPEN(s_chFileName, "wb+");
  if (fp) {
    OS_FWRITE(&g_stParamAdvInfo, sizeof(ParamAdvInfo_t), 1, fp);
    OS_FCLOSE(fp);
  }
  MUTEX_UNLOCK(g_lockParam);
  return 0;
}

bool Param_IsDebugMode(ParamInfo_t *p) {
  return (bool)p->info.power_soc_disable;
}

void Param_SetDebugMode(ParamInfo_t *p, bool on) {
  p->info.power_soc_disable = (uint8_t)on;
}

bool Param_IsFactoryMode(ParamInfo_t *p) { return (bool)p->info.factory_mode; }

void Param_SetFactoryMode(ParamInfo_t *p, bool on) {
  p->info.factory_mode = (uint8_t)on;
}
